home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / unzip.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  21KB  |  850 lines

  1. #include "unzip.h"
  2. #include "mame.h"
  3.  
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include <assert.h>
  8. #include <zlib.h>
  9.  
  10. /* public globals */
  11. int    gUnzipQuiet = 0;        /* flag controls error messages */
  12.  
  13.  
  14. #define ERROR_CORRUPT "The zipfile seems to be corrupt, please check it"
  15. #define ERROR_FILESYSTEM "Your filesystem seems to be corrupt, please check it"
  16. #define ERROR_UNSUPPORTED "The format of this zipfile is not supported, please recompress it"
  17.  
  18. #define INFLATE_INPUT_BUFFER_MAX 16384
  19. #ifndef MIN
  20. #define MIN(x,y) ((x)<(y)?(x):(y))
  21. #endif
  22.  
  23. /* Print a error message */
  24. void errormsg(const char* extmsg, const char* usermsg, const char* zipname) {
  25.     /* Output to the user with no internal detail */
  26.     if (!gUnzipQuiet)
  27.         printf("Error in zipfile %s\n%s\n", zipname, usermsg);
  28.     /* Output to log file with all informations */
  29.     logerror("Error in zipfile %s: %s\n", zipname, extmsg);
  30. }
  31.  
  32. /* -------------------------------------------------------------------------
  33.    Unzip support
  34.  ------------------------------------------------------------------------- */
  35.  
  36. /* Use these to avoid structure padding and byte-ordering problems */
  37. static UINT16 read_word (char *buf) {
  38.    unsigned char *ubuf = (unsigned char *) buf;
  39.  
  40.    return ((UINT16)ubuf[1] << 8) | (UINT16)ubuf[0];
  41. }
  42.  
  43. /* Use these to avoid structure padding and byte-ordering problems */
  44. static UINT32 read_dword (char *buf) {
  45.    unsigned char *ubuf = (unsigned char *) buf;
  46.  
  47.    return ((UINT32)ubuf[3] << 24) | ((UINT32)ubuf[2] << 16) | ((UINT32)ubuf[1] << 8) | (UINT32)ubuf[0];
  48. }
  49.  
  50. /* Locate end-of-central-dir sig in buffer and return offset
  51.    out:
  52.     *offset offset of cent dir start in buffer
  53.    return:
  54.     ==0 not found
  55.     !=0 found, *offset valid
  56. */
  57. static int ecd_find_sig (char *buffer, int buflen, int *offset)
  58. {
  59.     static char ecdsig[] = { 'P', 'K', 0x05, 0x06 };
  60.     int i;
  61.     for (i=buflen-22; i>=0; i--) {
  62.         if (memcmp(buffer+i, ecdsig, 4) == 0) {
  63.             *offset = i;
  64.             return 1;
  65.         }
  66.     }
  67.     return 0;
  68. }
  69.  
  70. /* Read ecd data in zip structure
  71.    in:
  72.      zip->fp, zip->length zip file
  73.    out:
  74.      zip->ecd, zip->ecd_length ecd data
  75. */
  76. static int ecd_read(ZIP* zip) {
  77.     char* buf;
  78.     int buf_length = 1024; /* initial buffer length */
  79.  
  80.     while (1) {
  81.         int offset;
  82.  
  83.         if (buf_length > zip->length)
  84.             buf_length = zip->length;
  85.  
  86.         if (fseek(zip->fp, zip->length - buf_length, SEEK_SET) != 0) {
  87.             return -1;
  88.         }
  89.  
  90.         /* allocate buffer */
  91.         buf = (char*)malloc( buf_length );
  92.         if (!buf) {
  93.             return -1;
  94.         }
  95.  
  96.         if (fread( buf, buf_length, 1, zip->fp ) != 1) {
  97.             free(buf);
  98.             return -1;
  99.         }
  100.  
  101.         if (ecd_find_sig(buf, buf_length, &offset)) {
  102.             zip->ecd_length = buf_length - offset;
  103.  
  104.             zip->ecd = (char*)malloc( zip->ecd_length );
  105.             if (!zip->ecd) {
  106.                 free(buf);
  107.                 return -1;
  108.             }
  109.  
  110.             memcpy(zip->ecd, buf + offset, zip->ecd_length);
  111.  
  112.             free(buf);
  113.             return 0;
  114.         }
  115.  
  116.         free(buf);
  117.  
  118.         if (buf_length < zip->length) {
  119.             /* double buffer */
  120.             buf_length = 2*buf_length;
  121.  
  122.             logerror("Retry reading of zip ecd for %d bytes\n",buf_length);
  123.  
  124.         } else {
  125.             return -1;
  126.         }
  127.     }
  128. }
  129.  
  130. /* offsets in end of central directory structure */
  131. #define ZIPESIG        0x00
  132. #define ZIPEDSK        0x04
  133. #define ZIPECEN        0x06
  134. #define ZIPENUM        0x08
  135. #define ZIPECENN    0x0a
  136. #define ZIPECSZ        0x0c
  137. #define ZIPEOFST    0x10
  138. #define ZIPECOML    0x14
  139. #define ZIPECOM        0x16
  140.  
  141. /* offsets in central directory entry structure */
  142. #define ZIPCENSIG    0x0
  143. #define ZIPCVER        0x4
  144. #define ZIPCOS        0x5
  145. #define    ZIPCVXT        0x6
  146. #define    ZIPCEXOS    0x7
  147. #define ZIPCFLG        0x8
  148. #define ZIPCMTHD    0xa
  149. #define ZIPCTIM        0xc
  150. #define ZIPCDAT        0xe
  151. #define ZIPCCRC        0x10
  152. #define ZIPCSIZ        0x14
  153. #define ZIPCUNC        0x18
  154. #define ZIPCFNL        0x1c
  155. #define ZIPCXTL        0x1e
  156. #define ZIPCCML        0x20
  157. #define ZIPDSK        0x22
  158. #define ZIPINT        0x24
  159. #define ZIPEXT        0x26
  160. #define ZIPOFST        0x2a
  161. #define ZIPCFN        0x2e
  162.  
  163. /* offsets in local file header structure */
  164. #define ZIPLOCSIG    0x00
  165. #define ZIPVER        0x04
  166. #define ZIPGENFLG    0x06
  167. #define ZIPMTHD        0x08
  168. #define ZIPTIME        0x0a
  169. #define ZIPDATE        0x0c
  170. #define ZIPCRC        0x0e
  171. #define ZIPSIZE        0x12
  172. #define ZIPUNCMP    0x16
  173. #define ZIPFNLN        0x1a
  174. #define ZIPXTRALN    0x1c
  175. #define ZIPNAME        0x1e
  176.  
  177. /* Opens a zip stream for reading
  178.    return:
  179.      !=0 success, zip stream
  180.      ==0 error
  181. */
  182. ZIP* openzip(const char* zipfile) {
  183.     /* allocate */
  184.     ZIP* zip = (ZIP*)malloc( sizeof(ZIP) );
  185.     if (!zip) {
  186.         return 0;
  187.     }
  188.  
  189.     /* open */
  190.     zip->fp = fopen(zipfile, "rb");
  191.     if (!zip->fp) {
  192.         errormsg ("Opening for reading", ERROR_FILESYSTEM, zipfile);
  193.         free(zip);
  194.         return 0;
  195.     }
  196.  
  197.     /* go to end */
  198.     if (fseek(zip->fp, 0L, SEEK_END) != 0) {
  199.         errormsg ("Seeking to end", ERROR_FILESYSTEM, zipfile);
  200.         fclose(zip->fp);
  201.         free(zip);
  202.         return 0;
  203.     }
  204.  
  205.     /* get length */
  206.     zip->length = ftell(zip->fp);
  207.     if (zip->length < 0) {
  208.         errormsg ("Get file size", ERROR_FILESYSTEM, zipfile);
  209.         fclose(zip->fp);
  210.         free(zip);
  211.         return 0;
  212.     }
  213.     if (zip->length == 0) {
  214.         errormsg ("Empty file", ERROR_CORRUPT, zipfile);
  215.         fclose(zip->fp);
  216.         free(zip);
  217.         return 0;
  218.     }
  219.  
  220.     /* read ecd data */
  221.     if (ecd_read(zip)!=0) {
  222.         errormsg ("Reading ECD (end of central directory)", ERROR_CORRUPT, zipfile);
  223.         fclose(zip->fp);
  224.         free(zip);
  225.         return 0;
  226.     }
  227.  
  228.     /* compile ecd info */
  229.     zip->end_of_cent_dir_sig = read_dword (zip->ecd+ZIPESIG);
  230.     zip->number_of_this_disk = read_word (zip->ecd+ZIPEDSK);
  231.     zip->number_of_disk_start_cent_dir = read_word (zip->ecd+ZIPECEN);
  232.     zip->total_entries_cent_dir_this_disk = read_word (zip->ecd+ZIPENUM);
  233.     zip->total_entries_cent_dir = read_word (zip->ecd+ZIPECENN);
  234.     zip->size_of_cent_dir = read_dword (zip->ecd+ZIPECSZ);
  235.     zip->offset_to_start_of_cent_dir = read_dword (zip->ecd+ZIPEOFST);
  236.     zip->zipfile_comment_length = read_word (zip->ecd+ZIPECOML);
  237.     zip->zipfile_comment = zip->ecd+ZIPECOM;
  238.  
  239.     /* verify that we can work with this zipfile (no disk spanning allowed) */
  240.     if ((zip->number_of_this_disk != zip->number_of_disk_start_cent_dir) ||
  241.         (zip->total_entries_cent_dir_this_disk != zip->total_entries_cent_dir) ||
  242.         (zip->total_entries_cent_dir < 1)) {
  243.         errormsg("Cannot span disks", ERROR_UNSUPPORTED, zipfile);
  244.         free(zip->ecd);
  245.         fclose(zip->fp);
  246.         free(zip);
  247.         return 0;
  248.     }
  249.  
  250.     if (fseek(zip->fp, zip->offset_to_start_of_cent_dir, SEEK_SET)!=0) {
  251.         errormsg ("Seeking to central directory", ERROR_CORRUPT, zipfile);
  252.         free(zip->ecd);
  253.         fclose(zip->fp);
  254.         free(zip);
  255.         return 0;
  256.     }
  257.  
  258.     /* read from start of central directory */
  259.     zip->cd = (char*)malloc( zip->size_of_cent_dir );
  260.     if (!zip->cd) {
  261.         free(zip->ecd);
  262.         fclose(zip->fp);
  263.         free(zip);
  264.         return 0;
  265.     }
  266.  
  267.     if (fread(zip->cd, zip->size_of_cent_dir, 1, zip->fp)!=1) {
  268.         errormsg ("Reading central directory", ERROR_CORRUPT, zipfile);
  269.         free(zip->cd);
  270.         free(zip->ecd);
  271.         fclose(zip->fp);
  272.         free(zip);
  273.         return 0;
  274.     }
  275.  
  276.     /* reset ent */
  277.     zip->ent.name = 0;
  278.  
  279.     /* rewind */
  280.     zip->cd_pos = 0;
  281.  
  282.     /* file name */
  283.     zip->zip = (char*)malloc(strlen(zipfile)+1);
  284.     if (!zip->zip) {
  285.         free(zip->cd);
  286.         free(zip->ecd);
  287.         fclose(zip->fp);
  288.         free(zip);
  289.         return 0;
  290.     }
  291.     strcpy(zip->zip, zipfile);
  292.  
  293.     return zip;
  294. }
  295.  
  296. /* Reads the current entry from a zip stream
  297.    in:
  298.      zip opened zip
  299.    return:
  300.      !=0 success
  301.      ==0 error
  302. */
  303. struct zipent* readzip(ZIP* zip) {
  304.  
  305.     /* end of directory */
  306.     if (zip->cd_pos >= zip->size_of_cent_dir)
  307.         return 0;
  308.  
  309.     /* compile zipent info */
  310.     zip->ent.cent_file_header_sig = read_dword (zip->cd+zip->cd_pos+ZIPCENSIG);
  311.     zip->ent.version_made_by = *(zip->cd+zip->cd_pos+ZIPCVER);
  312.     zip->ent.host_os = *(zip->cd+zip->cd_pos+ZIPCOS);
  313.     zip->ent.version_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCVXT);
  314.     zip->ent.os_needed_to_extract = *(zip->cd+zip->cd_pos+ZIPCEXOS);
  315.     zip->ent.general_purpose_bit_flag = read_word (zip->cd+zip->cd_pos+ZIPCFLG);
  316.     zip->ent.compression_method = read_word (zip->cd+zip->cd_pos+ZIPCMTHD);
  317.     zip->ent.last_mod_file_time = read_word (zip->cd+zip->cd_pos+ZIPCTIM);
  318.     zip->ent.last_mod_file_date = read_word (zip->cd+zip->cd_pos+ZIPCDAT);
  319.     zip->ent.crc32 = read_dword (zip->cd+zip->cd_pos+ZIPCCRC);
  320.     zip->ent.compressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCSIZ);
  321.     zip->ent.uncompressed_size = read_dword (zip->cd+zip->cd_pos+ZIPCUNC);
  322.     zip->ent.filename_length = read_word (zip->cd+zip->cd_pos+ZIPCFNL);
  323.     zip->ent.extra_field_length = read_word (zip->cd+zip->cd_pos+ZIPCXTL);
  324.     zip->ent.file_comment_length = read_word (zip->cd+zip->cd_pos+ZIPCCML);
  325.     zip->ent.disk_number_start = read_word (zip->cd+zip->cd_pos+ZIPDSK);
  326.     zip->ent.internal_file_attrib = read_word (zip->cd+zip->cd_pos+ZIPINT);
  327.     zip->ent.external_file_attrib = read_dword (zip->cd+zip->cd_pos+ZIPEXT);
  328.     zip->ent.offset_lcl_hdr_frm_frst_disk = read_dword (zip->cd+zip->cd_pos+ZIPOFST);
  329.  
  330.     /* check to see if filename length is illegally long (past the size of this directory
  331.        entry) */
  332.     if (zip->cd_pos + ZIPCFN + zip->ent.filename_length > zip->size_of_cent_dir)
  333.     {
  334.         errormsg("Invalid filename length in directory", ERROR_CORRUPT,zip->zip);
  335.         return 0;
  336.     }
  337.  
  338.     /* copy filename */
  339.     free(zip->ent.name);
  340.     zip->ent.name = (char*)malloc(zip->ent.filename_length + 1);
  341.     memcpy(zip->ent.name, zip->cd+zip->cd_pos+ZIPCFN, zip->ent.filename_length);
  342.     zip->ent.name[zip->ent.filename_length] = 0;
  343.  
  344.     /* skip to next entry in central dir */
  345.     zip->cd_pos += ZIPCFN + zip->ent.filename_length + zip->ent.extra_field_length + zip->ent.file_comment_length;
  346.  
  347.     return &zip->ent;
  348. }
  349.  
  350. /* Closes a zip stream */
  351. void closezip(ZIP* zip) {
  352.     /* release all */
  353.     free(zip->ent.name);
  354.     free(zip->cd);
  355.     free(zip->ecd);
  356.     /* only if not suspended */
  357.     if (zip->fp)
  358.         fclose(zip->fp);
  359.     free(zip->zip);
  360.     free(zip);
  361. }
  362.  
  363. /* Suspend access to a zip file (release file handler)
  364.    in:
  365.       zip opened zip
  366.    note:
  367.      A suspended zip is automatically reopened at first call of
  368.      readuncompressd() or readcompressed() functions
  369. */
  370. void suspendzip(ZIP* zip) {
  371.     if (zip->fp) {
  372.         fclose(zip->fp);
  373.         zip->fp = 0;
  374.     }
  375. }
  376.  
  377. /* Revive a suspended zip file (reopen file handler)
  378.    in:
  379.      zip suspended zip
  380.    return:
  381.     zip success
  382.     ==0 error (zip must be closed with closezip)
  383. */
  384. static ZIP* revivezip(ZIP* zip) {
  385.     if (!zip->fp) {
  386.         zip->fp = fopen(zip->zip, "rb");
  387.         if (!zip->fp) {
  388.             return 0;
  389.         }
  390.     }
  391.     return zip;
  392.  
  393. }
  394.  
  395. /* Reset a zip stream to the first entry
  396.    in:
  397.      zip opened zip
  398.    note:
  399.      ZIP file must be opened and not suspended
  400. */
  401. void rewindzip(ZIP* zip) {
  402.     zip->cd_pos = 0;
  403. }
  404.  
  405. /* Seek zip->fp to compressed data
  406.    return:
  407.     ==0 success
  408.     <0 error
  409. */
  410. int seekcompresszip(ZIP* zip, struct zipent* ent) {
  411.     char buf[ZIPNAME];
  412.     long offset;
  413.  
  414.     if (!zip->fp) {
  415.         if (!revivezip(zip))
  416.             return -1;
  417.     }
  418.  
  419.     if (fseek(zip->fp, ent->offset_lcl_hdr_frm_frst_disk, SEEK_SET)!=0) {
  420.         errormsg ("Seeking to header", ERROR_CORRUPT, zip->zip);
  421.         return -1;
  422.     }
  423.  
  424.     if (fread(buf, ZIPNAME, 1, zip->fp)!=1) {
  425.         errormsg ("Reading header", ERROR_CORRUPT, zip->zip);
  426.         return -1;
  427.     }
  428.  
  429.     {
  430.         UINT16 filename_length = read_word (buf+ZIPFNLN);
  431.         UINT16 extra_field_length = read_word (buf+ZIPXTRALN);
  432.  
  433.         /* calculate offset to data and fseek() there */
  434.         offset = ent->offset_lcl_hdr_frm_frst_disk + ZIPNAME + filename_length + extra_field_length;
  435.  
  436.         if (fseek(zip->fp, offset, SEEK_SET) != 0) {
  437.             errormsg ("Seeking to compressed data", ERROR_CORRUPT, zip->zip);
  438.             return -1;
  439.         }
  440.  
  441.     }
  442.  
  443.     return 0;
  444. }
  445.  
  446. /* Inflate a file
  447.    in:
  448.    in_file stream to inflate
  449.    in_size size of the compressed data to read
  450.    out_size size of decompressed data
  451.    out:
  452.    out_data buffer for decompressed data
  453.    return:
  454.    ==0 ok
  455.  
  456.    990525 rewritten for use with zlib MLR
  457. */
  458. static int inflate_file(FILE* in_file, unsigned in_size, unsigned char* out_data, unsigned out_size)
  459. {
  460.     int err;
  461.     unsigned char* in_buffer;
  462.     z_stream d_stream; /* decompression stream */
  463.  
  464.     d_stream.zalloc = 0;
  465.     d_stream.zfree = 0;
  466.     d_stream.opaque = 0;
  467.  
  468.     d_stream.next_in  = 0;
  469.     d_stream.avail_in = 0;
  470.     d_stream.next_out = out_data;
  471.     d_stream.avail_out = out_size;
  472.  
  473.     err = inflateInit2(&d_stream, -MAX_WBITS);
  474.     /* windowBits is passed < 0 to tell that there is no zlib header.
  475.      * Note that in this case inflate *requires* an extra "dummy" byte
  476.      * after the compressed stream in order to complete decompression and
  477.      * return Z_STREAM_END.
  478.      */
  479.     if (err != Z_OK)
  480.     {
  481.         logerror("inflateInit error: %d\n", err);
  482.         return -1;
  483.     }
  484.  
  485.     in_buffer = (unsigned char*)malloc(INFLATE_INPUT_BUFFER_MAX+1);
  486.     if (!in_buffer)
  487.         return -1;
  488.  
  489.     for (;;)
  490.     {
  491.         if (in_size <= 0)
  492.         {
  493.             logerror("inflate error: compressed size too small\n");
  494.             free (in_buffer);
  495.             return -1;
  496.         }
  497.         d_stream.next_in  = in_buffer;
  498.         d_stream.avail_in = fread (in_buffer, 1, MIN(in_size, INFLATE_INPUT_BUFFER_MAX), in_file);
  499.         in_size -= d_stream.avail_in;
  500.         if (in_size == 0)
  501.             d_stream.avail_in++; /* add dummy byte at end of compressed data */
  502.  
  503.         err = inflate(&d_stream, Z_NO_FLUSH);
  504.         if (err == Z_STREAM_END)
  505.             break;
  506.         if (err != Z_OK)
  507.         {
  508.             logerror("inflate error: %d\n", err);
  509.             free (in_buffer);
  510.             return -1;
  511.         }
  512.     }
  513.  
  514.     err = inflateEnd(&d_stream);
  515.     if (err != Z_OK)
  516.     {
  517.         logerror("inflateEnd error: %d\n", err);
  518.         free (in_buffer);
  519.         return -1;
  520.     }
  521.  
  522.     free (in_buffer);
  523.  
  524.     if ((d_stream.avail_out > 0) || (in_size > 0))
  525.     {
  526.         logerror("zip size mismatch. %i\n", in_size);
  527.         return -1;
  528.     }
  529.  
  530.     return 0;
  531. }
  532.  
  533. /* Read compressed data
  534.    out:
  535.     data compressed data read
  536.    return:
  537.     ==0 success
  538.     <0 error
  539. */
  540. int readcompresszip(ZIP* zip, struct zipent* ent, char* data) {
  541.     int err = seekcompresszip(zip,ent);
  542.     if (err!=0)
  543.         return err;
  544.  
  545.     if (fread(data, ent->compressed_size, 1, zip->fp)!=1) {
  546.         errormsg ("Reading compressed data", ERROR_CORRUPT, zip->zip);
  547.         return -1;
  548.     }
  549.  
  550.     return 0;
  551. }
  552.  
  553. /* Read UNcompressed data
  554.    out:
  555.     data UNcompressed data
  556.    return:
  557.     ==0 success
  558.     <0 error
  559. */
  560. int readuncompresszip(ZIP* zip, struct zipent* ent, char* data) {
  561.     if (ent->compression_method == 0x0000) {
  562.         /* file is not compressed, simply stored */
  563.  
  564.         /* check if size are equal */
  565.         if (ent->compressed_size != ent->uncompressed_size) {
  566.             errormsg("Wrong uncompressed size in store compression", ERROR_CORRUPT,zip->zip);
  567.             return -3;
  568.         }
  569.  
  570.         return readcompresszip(zip,ent,data);
  571.     } else if (ent->compression_method == 0x0008) {
  572.         /* file is compressed using "Deflate" method */
  573.         if (ent->version_needed_to_extract > 0x14) {
  574.             errormsg("Version too new", ERROR_UNSUPPORTED,zip->zip);
  575.             return -2;
  576.         }
  577.  
  578.         if (ent->os_needed_to_extract != 0x00) {
  579.             errormsg("OS not supported", ERROR_UNSUPPORTED,zip->zip);
  580.             return -2;
  581.         }
  582.  
  583.         if (ent->disk_number_start != zip->number_of_this_disk) {
  584.             errormsg("Cannot span disks", ERROR_UNSUPPORTED,zip->zip);
  585.             return -2;
  586.         }
  587.  
  588.         /* read compressed data */
  589.         if (seekcompresszip(zip,ent)!=0) {
  590.             return -1;
  591.         }
  592.  
  593.         /* configure inflate */
  594.         if (inflate_file( zip->fp, ent->compressed_size, (unsigned char*)data, ent->uncompressed_size))
  595.         {
  596.             errormsg("Inflating compressed data", ERROR_CORRUPT, zip->zip);
  597.             return -3;
  598.         }
  599.  
  600.         return 0;
  601.     } else {
  602.         errormsg("Compression method unsupported", ERROR_UNSUPPORTED, zip->zip);
  603.         return -2;
  604.     }
  605. }
  606.  
  607. /* -------------------------------------------------------------------------
  608.    Zip cache support
  609.  ------------------------------------------------------------------------- */
  610.  
  611. /* Use the zip cache */
  612. #define ZIP_CACHE
  613.  
  614. #ifdef ZIP_CACHE
  615.  
  616. /* ZIP cache entries */
  617. #define ZIP_CACHE_MAX 2
  618.  
  619. /* ZIP cache buffer LRU ( Last Recently Used )
  620.      zip_cache_map[0] is the newer
  621.      zip_cache_map[ZIP_CACHE_MAX-1] is the older
  622. */
  623. static ZIP* zip_cache_map[ZIP_CACHE_MAX];
  624.  
  625. static ZIP* cache_openzip(const char* zipfile) {
  626.     ZIP* zip;
  627.     unsigned i;
  628.  
  629.     /* search in the cache buffer */
  630.     for(i=0;i<ZIP_CACHE_MAX;++i) {
  631.         if (zip_cache_map[i] && strcmp(zip_cache_map[i]->zip,zipfile)==0) {
  632.             /* found */
  633.             unsigned j;
  634.  
  635. /*
  636.             logerror("Zip cache HIT  for %s\n", zipfile);
  637. */
  638.  
  639.             /* reset the zip directory */
  640.             rewindzip( zip_cache_map[i] );
  641.  
  642.             /* store */
  643.             zip = zip_cache_map[i];
  644.  
  645.             /* shift */
  646.             for(j=i;j>0;--j)
  647.                 zip_cache_map[j] = zip_cache_map[j-1];
  648.  
  649.             /* set the first entry */
  650.             zip_cache_map[0] = zip;
  651.  
  652.             return zip_cache_map[0];
  653.         }
  654.     }
  655.     /* not found */
  656.  
  657. /*
  658.     logerror("Zip cache FAIL for %s\n", zipfile);
  659. */
  660.  
  661.     /* open the zip */
  662.     zip = openzip( zipfile );
  663.     if (!zip)
  664.         return 0;
  665.  
  666.     /* close the oldest entry */
  667.     if (zip_cache_map[ZIP_CACHE_MAX-1]) {
  668.         /* close last zip */
  669.         closezip(zip_cache_map[ZIP_CACHE_MAX-1]);
  670.         /* reset the entry */
  671.         zip_cache_map[ZIP_CACHE_MAX-1] = 0;
  672.     }
  673.  
  674.     /* shift */
  675.     for(i=ZIP_CACHE_MAX-1;i>0;--i)
  676.         zip_cache_map[i] = zip_cache_map[i-1];
  677.  
  678.     /* set the first entry */
  679.     zip_cache_map[0] = zip;
  680.  
  681.     return zip_cache_map[0];
  682. }
  683.  
  684. static void cache_closezip(ZIP* zip) {
  685.     unsigned i;
  686.  
  687.     /* search in the cache buffer */
  688.     for(i=0;i<ZIP_CACHE_MAX;++i) {
  689.         if (zip_cache_map[i]==zip) {
  690.             /* close zip */
  691.             closezip(zip);
  692.  
  693.             /* reset cache entry */
  694.             zip_cache_map[i] = 0;
  695.             return;
  696.  
  697.         }
  698.     }
  699.     /* not found */
  700.  
  701.     /* close zip */
  702.     closezip(zip);
  703. }
  704.  
  705. /* CK980415 added to allow osd code to clear zip cache for auditing--each time
  706.    the user opens up an audit for a game we should reread the zip */
  707. void unzip_cache_clear()
  708. {
  709.     unsigned i;
  710.  
  711.     /* search in the cache buffer for any zip info and clear it */
  712.     for(i=0;i<ZIP_CACHE_MAX;++i) {
  713.         if (zip_cache_map[i] != NULL) {
  714.             /* close zip */
  715.             closezip(zip_cache_map[i]);
  716.  
  717.             /* reset cache entry */
  718.             zip_cache_map[i] = 0;
  719. /*            return; */
  720.  
  721.         }
  722.     }
  723. }
  724.  
  725. #define cache_suspendzip(a) suspendzip(a)
  726.  
  727. #else
  728.  
  729. #define cache_openzip(a) openzip(a)
  730. #define cache_closezip(a) closezip(a)
  731. #define cache_suspendzip(a) closezip(a)
  732.  
  733. #define unzip_cache_clear()
  734.  
  735. #endif
  736.  
  737. /* -------------------------------------------------------------------------
  738.    Backward MAME compatibility
  739.  ------------------------------------------------------------------------- */
  740.  
  741. /* Compare two filename
  742.    note:
  743.      don't check directory in zip and ignore case
  744. */
  745. static int equal_filename(const char* zipfile, const char* file) {
  746.     const char* s1 = file;
  747.     /* start comparison after last / */
  748.     const char* s2 = strrchr(zipfile,'/');
  749.     if (s2)
  750.         ++s2;
  751.     else
  752.         s2 = zipfile;
  753.     while (*s1 && toupper(*s1)==toupper(*s2)) {
  754.         ++s1;
  755.         ++s2;
  756.     }
  757.     return !*s1 && !*s2;
  758. }
  759.  
  760. /* Pass the path to the zipfile and the name of the file within the zipfile.
  761.    buf will be set to point to the uncompressed image of that zipped file.
  762.    length will be set to the length of the uncompressed data. */
  763. int /* error */ load_zipped_file (const char* zipfile, const char* filename, unsigned char** buf, unsigned int* length) {
  764.     ZIP* zip;
  765.     struct zipent* ent;
  766.  
  767.     zip = cache_openzip(zipfile);
  768.     if (!zip)
  769.         return -1;
  770.  
  771.     while (readzip(zip)) {
  772.         /* NS981003: support for "load by CRC" */
  773.         char crc[9];
  774.  
  775.         ent = &(zip->ent);
  776.  
  777.         sprintf(crc,"%08x",ent->crc32);
  778.         if (equal_filename(ent->name, filename) ||
  779.                 (ent->crc32 && !strcmp(crc, filename)))
  780.         {
  781.             *length = ent->uncompressed_size;
  782.             *buf = (unsigned char*)malloc( *length );
  783.             if (!*buf) {
  784.                 if (!gUnzipQuiet)
  785.                     printf("load_zipped_file(): Unable to allocate %d bytes of RAM\n",*length);
  786.                 cache_closezip(zip);
  787.                 return -1;
  788.             }
  789.  
  790.             if (readuncompresszip(zip, ent, (char*)*buf)!=0) {
  791.                 free(*buf);
  792.                 cache_closezip(zip);
  793.                 return -1;
  794.             }
  795.  
  796.             cache_suspendzip(zip);
  797.             return 0;
  798.         }
  799.     }
  800.  
  801.     cache_suspendzip(zip);
  802.     return -1;
  803. }
  804.  
  805. /*    Pass the path to the zipfile and the name of the file within the zipfile.
  806.     sum will be set to the CRC-32 of that zipped file. */
  807. /*  The caller can preset sum to the expected checksum to enable "load by CRC" */
  808. int /* error */ checksum_zipped_file (const char *zipfile, const char *filename, unsigned int *length, unsigned int *sum) {
  809.     ZIP* zip;
  810.     struct zipent* ent;
  811.  
  812.     zip = cache_openzip(zipfile);
  813.     if (!zip)
  814.         return -1;
  815.  
  816.     while (readzip(zip)) {
  817.         ent = &(zip->ent);
  818.  
  819.         if (equal_filename(ent->name, filename))
  820.         {
  821.             *length = ent->uncompressed_size;
  822.             *sum = ent->crc32;
  823.             cache_suspendzip(zip);
  824.             return 0;
  825.         }
  826.     }
  827.  
  828.     cache_suspendzip(zip);
  829.  
  830.     /* NS981003: support for "load by CRC" */
  831.     zip = cache_openzip(zipfile);
  832.     if (!zip)
  833.         return -1;
  834.  
  835.     while (readzip(zip)) {
  836.         ent = &(zip->ent);
  837.  
  838.         if (*sum && ent->crc32 == *sum)
  839.         {
  840.             *length = ent->uncompressed_size;
  841.             *sum = ent->crc32;
  842.             cache_suspendzip(zip);
  843.             return 0;
  844.         }
  845.     }
  846.  
  847.     cache_suspendzip(zip);
  848.     return -1;
  849. }
  850.